import { create } from "zustand";
import { createWithEqualityFn } from "zustand/traditional";
import { produce } from "immer";
import cookie from "js-cookie";
import { persist } from "zustand/middleware";

// import debounce from 'lodash-es/debounce'
import {
  addCustomization,
  delContent,
  delEntry,
  editSectionName,
  updatePersonalDetail,
} from "../service/index";
import { debounce, isProd } from "../app/utils";
import {
  content,
  customization,
  initialState,
  personalDetails,
} from "./initialState";
import {
  addContent,
  addEntry,
  addResumeDetail,
  editContent,
  editEntry,
  getResumeDetail,
  sortEntry,
  toggleHideEntry,
} from "@/service";

interface Action {
  update: (content: any) => void;
  add?: (content: any) => void;
  delete?: (content: any) => void;
}

function needLogin() {
  const token = cookie.get("baijie_token");
  const id = new URLSearchParams(location.search).get("id");
  if (!token && !id) {
    return false;
  }
  return true;
}

export const usePersonalDetailsStore = createWithEqualityFn<
  { personalDetails: PersonalDetails } & { id?: number } & Action & {
      updateDetailOrder: (data: (keyof PersonalDetails)[]) => void;
      // updatePhoto: (data: { showPhoto?: boolean; shape?: string }) => void
      updateDetail: (data: PersonalDetails) => void;
    }
>()(
  persist(
    (set) => ({
      personalDetails,
      update: (data: any) => {
        set(() => ({ personalDetails: data }));
      },
      updateDetail: (data) => {
        set((state) => ({
          personalDetails: {
            ...state.personalDetails,
            ...data,
          },
        }));
      },
      updateDetailOrder: (data) => {
        set((state) => ({
          personalDetails: {
            ...state.personalDetails,
            detailsOrder: data,
          },
        }));
      },
    }),
    {
      name: "personalDetails",
      skipHydration: false,
      // storage: {
      //   setItem(name, value) {
      //     if (isClient()) {
      //       if (!value.state.personalDetails.id) {
      //         localStorage.setItem(name, JSON.stringify(value))
      //       }
      //     }
      //   },
      //   getItem(name) {
      //     return JSON.parse(localStorage.getItem(name))
      //   },
      //   removeItem() {},
      // },
    }
  )
);

export const useCustomizationStore = createWithEqualityFn<
  { customization: Customization } & Action & {
      updateLayout: (data: Layout) => void;
      updateSectionOrder: (data: SectionOrder) => void;
      updateTemp: (data: Customization) => void;
      updateHeader: (data: Header) => void;
      updateSpacing: (data: Spacing) => void;
      updateColors: (data: Colors) => void;
      updatetTitle: (data: Title) => void;
      updateAccentColor: (data: string[]) => void;
      addCustomization: (resumeId: number) => void;
      updateColumnWidth: (colWidthsFromDetails: ColWidthsFromDetails) => void;
    }
>()(
  persist(
    (set) => {
      return {
        customization,
        update: (data) => {
          set(() => ({ customization: data }));
        },
        updateLayout: (data) => {
          set((state) => ({
            customization: {
              ...state.customization,
              layout: data,
            },
          }));
        },
        updateColumnWidth: (data) => {
          set((state) => ({
            customization: {
              ...state.customization,
              layout: {
                ...state.customization.layout,
                colWidthsFromDetails: data,
              },
            },
          }));
        },
        updateSpacing: (data) => {
          set((state) => ({
            customization: {
              ...state.customization,
              spacing: data,
            },
          }));
        },
        updateSectionOrder: (data) => {
          set((state) => ({
            customization: {
              ...state.customization,
              sectionOrder: produce(data, (draft) => {
                draft.one.leftSectionChildren = [
                  ...new Set(draft.one.leftSectionChildren),
                ];
                draft.two.leftSectionChildren = [
                  ...new Set(draft.two.leftSectionChildren),
                ];
                draft.two.rightSectionChildren = [
                  ...new Set(draft.two.rightSectionChildren),
                ];
              }),
            },
          }));
        },
        updateTemp: (data: Customization) => {
          set((state) => ({
            customization: {
              ...state.customization,
              ...data,
            },
          }));
        },
        updateHeader: (data: any) => {
          set((state) => ({
            customization: {
              ...state.customization,
              header: {
                ...state.customization.header,
                ...data,
              },
            },
          }));
        },
        updateColors: (data: any) => {
          set((state) => ({
            customization: {
              ...state.customization,
              colors: data,
            },
          }));
        },
        updatetTitle: (data: Title) => {
          set((state) => ({
            customization: {
              ...state.customization,
              title: data,
            },
          }));
        },
        updateAccentColor: (data: any) => {
          set((state) => ({
            customization: {
              ...state.customization,
              applyAccentColor: data,
            },
          }));
        },
        addCustomization: debounce(async (resumeId) => {
          const { customization } = useCustomizationStore.getState();
          await addCustomization({
            resumeId,
            customization,
          });
          const data = await getResumeDetail({ id: resumeId });
          hydrateStore(data.data);
        }, 800),
      };
    },
    {
      name: "customization",
      skipHydration: false,
      // storage: {
      //   setItem(name, value) {
      //     if (isClient()) {
      //       const { personalDetails } = usePersonalDetailsStore.getState()
      //       if (!personalDetails.id) {
      //         localStorage.setItem(name, JSON.stringify(value))
      //       }
      //     }
      //   },
      //   getItem(name) {
      //     const { personalDetails } = usePersonalDetailsStore.getState()
      //     if (!personalDetails.id) {
      //       return JSON.parse(localStorage.getItem(name))
      //     }
      //   },
      //   removeItem() {},
      // },
    }
  )
);

export const useContentStore = createWithEqualityFn<
  { content: ResumesContent } & {
    updateAll: (content: ResumesContent) => void;
    updateSection?: (content: Content, type: Sections) => void;
    addContent?: (content: Content, type: Sections) => void;
    deleteContent?: (type: Sections) => void;
  }
>()(
  persist(
    (set, get) => ({
      content,
      updateAll: (data: ResumesContent) => {
        set(() => ({ content: data }));
      },
      updateSection: (data, type) => {
        set((state) => ({
          content: {
            ...state.content,
            [type]: data,
          },
        }));
      },
      addContent: (data: Content, type: Sections) => {
        // const { add, delete: d, update: u, ...rest } = data
        const { updateSectionOrder, customization } =
          useCustomizationStore.getState();
        const contentKeys = Object.keys(get().content);
        const newCustomization = produce(customization, (draft) => {
          const { one, two } = draft.sectionOrder;
          const needInsertSection = type;
          if (needInsertSection) {
            const onekeys = one.leftSectionChildren.filter((v) =>
              contentKeys.includes(v)
            );
            // if (index !== -1) {
            // one.leftSectionChildren.splice(contentKeys.length, 0, needInsertSection)
            one.leftSectionChildren = [
              ...new Set([
                ...onekeys,
                needInsertSection,
                ...one.leftSectionChildren,
              ]),
            ];
            // }
            // else {
            //   one.leftSectionChildren.push(needInsertSection)
            // }

            if (two.leftSectionChildren.includes(needInsertSection)) {
              const two_l_keys = two.leftSectionChildren.filter((v) =>
                contentKeys.includes(v)
              );

              // const leftKeys = two.leftSectionChildren.filter(v => contentKeys.includes(v))
              // two.leftSectionChildren.splice(leftKeys.length, 0, needInsertSection)
              // two.leftSectionChildren = [...new Set(two.leftSectionChildren)]
              two.leftSectionChildren = [
                ...new Set([
                  ...two_l_keys,
                  needInsertSection,
                  ...two.leftSectionChildren,
                ]),
              ];
            }

            if (two.rightSectionChildren.includes(needInsertSection)) {
              const two_r_keys = two.rightSectionChildren.filter((v) =>
                contentKeys.includes(v)
              );
              // const leftKeys = two.rightSectionChildren.filter(v => contentKeys.includes(v))
              // two.rightSectionChildren.splice(leftKeys.length, 0, needInsertSection)
              // two.rightSectionChildren = [...new Set(two.rightSectionChildren)]
              two.rightSectionChildren = [
                ...new Set([
                  ...two_r_keys,
                  needInsertSection,
                  ...two.rightSectionChildren,
                ]),
              ];
            }
            if (
              !two.leftSectionChildren.includes(needInsertSection) &&
              !two.rightSectionChildren.includes(needInsertSection)
            ) {
              if (draft.layout.detailsPosition === "left") {
                two.rightSectionChildren.push(needInsertSection);
              } else {
                two.leftSectionChildren.push(needInsertSection);
              }
            }
          }
        });
        updateSectionOrder(newCustomization.sectionOrder);
        set((state) => ({
          content: {
            ...state.content,
            [type]: data,
          },
        }));
      },
      deleteContent: (type: Sections) => {
        // const { update: customizationUpdate, customization } = useCustomizationStore.getState()
        // customizationUpdate(produce(customization, (draft) => {
        //   const { one, two } = draft.sectionOrder
        //   const needDeleteSection = type
        //   if (needDeleteSection) {
        //     const i = one.leftSectionChildren.indexOf(needDeleteSection)
        //     if (i !== -1) {
        //       one.leftSectionChildren.splice(i, 1)
        //     }

        //     const y = two.rightSectionChildren.indexOf(needDeleteSection)
        //     if (y !== -1) {
        //       two.rightSectionChildren.splice(y, 1)
        //     }

        //     const z = two.leftSectionChildren.indexOf(needDeleteSection)
        //     if (z !== -1) {
        //       two.leftSectionChildren.splice(z, 1)
        //     }
        //   }
        // }))
        set((state) => {
          const content = { ...state.content };
          delete content[type];
          return {
            content,
          };
        });
      },
    }),
    {
      name: "content",
      skipHydration: false,
    }
  )
);

interface IAction {
  setCurrentTab: (d: string) => void;
  setIndex: (d: number) => void;
  setShowLogin: (d: boolean) => void;
  setIsLogin: (d: boolean) => void;
  setHtml: (html: string) => void;
  setDownloading: (loading: boolean) => void;
  setFontScale: (fontScale: number) => void;
  setMyResumes: (myResumes: any[]) => void;
  setTempInfo: (p: tempInfo) => void;
  setWordList: (p: any[]) => void;
}
interface tempInfo {
  title: string;
  description: string;
  templateName: string;
  // default: number
  order: number;
  // show: number
  classify: number;
}
export const useStore = createWithEqualityFn<
  {
    currentTab: string;
    index: number;
    showLogin: boolean;
    isLogin: boolean;
    htmlString: string;
    downloading: boolean;
    isMobile: boolean;
    isWeixin: boolean;
    fontScale: number;
    myResumes: any[];
    wordList: any[];
    tempInfo: tempInfo;
  } & IAction
>()((set, get) => ({
  currentTab: "content",
  showLogin: false,
  isLogin: false,
  downloading: false,
  htmlString: "",
  isMobile: false,
  isWeixin: false,
  index: 0,
  fontScale: 1,
  myResumes: [],
  wordList: [],
  tempInfo: {
    title: "",
    description: "",
    templateName: "tpl1",
    order: 0,
    classify: 0,
  },

  setShowLogin: (data) => {
    set((state) => ({ showLogin: data }));
  },
  setIsLogin: (data) => {
    set((state) => ({ isLogin: data }));
  },
  setCurrentTab: (data) => {
    set((state) => ({ currentTab: data }));
  },
  setIndex: (data) => {
    set((state) => ({ index: data }));
  },
  setHtml: (html) => {
    set((state) => ({ htmlString: html }));
  },
  setDownloading: (loading) => {
    set((state) => ({ downloading: loading }));
  },
  setFontScale: (fontScale) => {
    set((state) => ({ fontScale }));
  },
  setMyResumes: (myResumes) => {
    set((state) => ({ myResumes }));
  },

  setTempInfo: (tempInfo) => {
    set((state) => ({ tempInfo }));
  },
  setWordList: (wordList) => {
    set((state) => ({ wordList }));
  },
}));

interface ServerAction {
  saveAll: () => any;
  save: (content?: Content) => any;
  editEntry: (data: Entries, type: Sections) => any;
  editSectionName: (data: Content) => any;
  addEntry: (data: Entries, content: Content) => any;
  delEntry: (data: Entries, content: Content) => any;
  addContent: (content: Content, resumeId: number) => any;
  editContent: (content: Content, resumeId: number) => any;
  toggleHideEntry: (data: { id: number; isHidden: boolean }) => any;
  sortEntry: (id: number, order: number[]) => any;
  updatePersonalDetail: (data: PersonalDetails) => any;
}

export const useServerStore = create<ServerAction>((set, get, api) => ({
  async saveAll() {
    const { content } = useContentStore.getState();
    const { customization } = useCustomizationStore.getState();
    const { personalDetails } = usePersonalDetailsStore.getState();
    const resume = {
      content: Object.values(content),
      customization,
      personalDetails,
    };
    // delete resume.customization.defaultSectionOrder
    const res = await addResumeDetail(resume);
    if (res?.code === 200) {
      const newUrl = `${window.location.pathname}?id=${res.data}`;
      window.history.replaceState({}, "title", newUrl);
      const data = await getResumeDetail({ id: res.data });
      hydrateStore(data.data);
      useStore.setState({ currentTab: "content" });
      return res;
    }
  },
  async save(data) {
    // if (!needLogin()) {
    //   useStore.setState({ currentTab: 'content' })
    //   return {
    //     code: 200,
    //   }
    // }
    const { personalDetails } = usePersonalDetailsStore.getState();
    if (personalDetails.id) {
      return await get().addContent({ ...data }, personalDetails.id);
    } else {
      return await get().saveAll();
    }
  },
  async addContent(d, resumeId) {
    // if (!needLogin()) {
    //   return {
    //     code: 200,
    //   }
    // }
    const { customization } = useCustomizationStore.getState();
    const { updateSection, content } = useContentStore.getState();
    const { sectionOrder } = customization;
    const res = await addContent({ content: d, sectionOrder, resumeId });
    if (res?.code === 200) {
      updateSection(
        produce(content[d.sectionType], (draft) => {
          draft.id = res.data.contentId;
          draft.entries[draft.entries.length - 1].id = res.data.entryId;
        }),
        d.sectionType
      );
      useStore.setState({ currentTab: "content" });
      return res;
    }
  },
  async editContent(d, contentId) {
    // if (!needLogin()) {
    //   return {
    //     code: 200,
    //   }
    // }
    const { personalDetails } = usePersonalDetailsStore.getState();
    return await editContent({
      ...d,
      id: contentId,
      resumeId: personalDetails.id,
    });
  },
  async editSectionName(data: Content) {
    return await editSectionName({
      id: data.id,
      displayName: data.displayName,
      iconKey: data.iconKey,
    });
  },
  async addEntry(data, c) {
    // if (!needLogin()) {
    //   return {
    //     code: 200,
    //   }
    // }
    const { updateSection, content } = useContentStore.getState();
    const res = await addEntry({
      ...data,
      order: c.entries.length - 1,
      contentId: c.id,
    });
    if (res?.code === 200) {
      updateSection(
        produce(content[c.sectionType], (draft) => {
          draft.entries[c.entries.length - 1].id = res.data.entryId;
        }),
        c.sectionType
      );
      useStore.setState({ currentTab: "content" });
      return res;
    }
  },
  async delEntry(data, content) {
    // if (!needLogin()) {
    //   return {
    //     code: 200,
    //   }
    // }
    if (content.entries.length <= 1) {
      const { deleteContent } = useContentStore.getState();
      const { personalDetails } = usePersonalDetailsStore.getState();
      // const { customization } = useCustomizationStore.getState()
      // const newCustomization = produce(customization, (draft) => {
      //   const { one, two } = draft.sectionOrder
      //   const needDeleteSection = content.sectionType
      //   if (needDeleteSection) {
      //     const i = one.leftSectionChildren.indexOf(needDeleteSection)
      //     if (i !== -1) {
      //       one.leftSectionChildren.splice(i, 1)
      //     }
      //     const y = two.rightSectionChildren.indexOf(needDeleteSection)
      //     if (y !== -1) {
      //       two.rightSectionChildren.splice(y, 1)
      //     }
      //     const z = two.leftSectionChildren.indexOf(needDeleteSection)
      //     if (z !== -1) {
      //       two.leftSectionChildren.splice(z, 1)
      //     }
      //   }
      // })
      if (content.id) {
        const res = await delContent({
          id: content.id,
          resumeId: personalDetails.id,
        });
        if (res?.code === 200) {
          deleteContent(content.sectionType);
          useStore.setState({ currentTab: "content" });
          return res;
        }
      } else {
        deleteContent(content.sectionType);
        useStore.setState({ currentTab: "content" });
      }
    } else {
      const { updateSection } = useContentStore.getState();
      if (data.id) {
        const res = await delEntry({ id: data.id, contentId: content.id });
        if (res?.code === 200) {
          updateSection(
            produce(content, (draft) => {
              const index = draft.entries.findIndex(
                (item) => item.id === data.id
              );
              draft.entries.splice(index, 1);
            }),
            content.sectionType
          );
          useStore.setState({ currentTab: "content" });
          return res;
        }
      } else {
        updateSection(
          produce(content, (draft) => {
            const index = draft.entries.findIndex(
              (item) => item.key === data.key
            );
            draft.entries.splice(index, 1);
          }),
          content.sectionType
        );
        useStore.setState({ currentTab: "content" });
      }
    }
  },
  async editEntry(data) {
    // if (!needLogin()) {
    //   return {
    //     code: 200,
    //   }
    // }
    const res = await editEntry({ ...data });
    if (res?.code === 200) {
      useStore.setState({ currentTab: "content" });
      return res;
    }
  },
  async toggleHideEntry(data) {
    if (!needLogin()) {
      return {
        code: 200,
      };
    }
    const { personalDetails } = usePersonalDetailsStore.getState();
    if (personalDetails.id) {
      const res = await toggleHideEntry({ ...data });
      if (res?.code === 200) {
        return res;
      }
    } else {
      return await get().saveAll();
    }
  },
  async sortEntry(contentId, newOrder) {
    // if (!needLogin()) {
    //   useStore.setState({ currentTab: 'content' })
    //   return {
    //     code: 200,
    //   }
    // }

    const { personalDetails } = usePersonalDetailsStore.getState();
    if (personalDetails.id) {
      const res = await sortEntry({
        contentId,
        newOrder,
      });
    } else {
      return await get().saveAll();
    }
  },
  async updatePersonalDetail(personalDetails) {
    if (personalDetails.id) {
      const obj = { ...personalDetails };
      for (const i in obj) {
        if (obj[i] == null || obj[i] === "") {
          obj[i] = null;
        }
      }
      const res = await updatePersonalDetail({ ...obj });
      if (res?.code === 200) {
        useStore.setState({ currentTab: "content" });
        return res;
      }
    }
  },
}));

export function hydrateStore(data: Resumes) {
  const state = data;
  if (state) {
    usePersonalDetailsStore.setState({
      personalDetails: state.personalDetails,
    });
    useContentStore.setState({ content: state.content });
    useCustomizationStore.setState({ customization: state.customization });
  } else {
    usePersonalDetailsStore.setState({
      personalDetails: initialState.personalDetails,
    });
    useContentStore.setState({ content: initialState.content });
    useCustomizationStore.setState({
      customization: initialState.customization,
    });
  }
  if (!isProd) {
    const tempInfo = {
      title: (data as any)?.title ?? "",
      description: (data as any)?.description ?? "",
      templateName: (data as any)?.templateName ?? "tpl1",
      order: (data as any)?.order ?? null,
      classify: (data as any)?.classify ?? null,
    };
    useStore.setState({ tempInfo });
  }
}
